#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/spi.h"
#include <string.h>
#include "wizchip_conf.h"
#include "w5500.h"
#include "w5500_spi.h"
#include "mqtt_interface.h"
#include "MQTTClient.h"

#define MQTT_SEND_BUFF_SIZE 2048 // MQTT协议发送报文缓存大小
#define MQTT_RECV_BUFF_SIZE 2048 // MQTT协议接收报文缓存大小
#define MQTT_SOCKET 1            // MQTT使用的SOCKET号

uint8_t mqtt_send_buff[MQTT_SEND_BUFF_SIZE] = {0}; // MQTT协议发送报文缓存
uint8_t mqtt_recv_buff[MQTT_RECV_BUFF_SIZE] = {0}; // MQTT协议接收报文缓存

// MQTT连接和订阅参数结构体
typedef struct MQTTCONNECTION
{
    uint8_t server_ip[4];
    int port;
    char clientid[1024];
    char username[1024];
    char passwd[1024];
    char pubtopic[255];
    char subtopic[255];
    int QOS;
} mqttconn;

// MQTT连接和订阅参数
mqttconn mqtt_params = {
    .server_ip = {54, 244, 173, 190},
    .port = 1883,
    .clientid = "9a1d7719a8ac40d29311f26c5c5469dc",
    .username = "mqtt_username",
    .passwd = "123456",
    .pubtopic = "W5500",
    .subtopic = "W5500",
    .QOS = 0,
};

// 网络地址信息
static wiz_NetInfo net_info = {
    .mac = {0x00, 0x08, 0xdc, 0x16, 0xed, 0x2e},
    .ip = {192, 168, 1, 20},
    .sn = {255, 255, 255, 0},
    .gw = {192, 168, 1, 1},
    .dns = {8, 8, 8, 8},
    .dhcp = NETINFO_STATIC};

MQTTClient c = {0}; // MQTT客户端连接信息结构体
Network n = {0};    // 网络信息结构体
int connOK;         //连接状态

bool repeating_timer_callback(struct repeating_timer *t); // 1ms定时器回调函数
void mqtt_init(void);                                     // mqtt连接函数
void messageArrived(MessageData *md);                     // mqtt消息回调函数
void keep_mqtt(void);                                     // mqtt保活函数

int main()
{
    struct repeating_timer timer;
    stdio_init_all();
    sleep_ms(3000);
    printf("W5500 mqtt example.\r\n");

    wizchip_initialize(); // SPI初始化以及链路状态检测

    wizchip_setnetinfo(&net_info); // 设置网络地址信息

    print_network_information(net_info);                               // 打印网络地址信息
    add_repeating_timer_ms(1, repeating_timer_callback, NULL, &timer); // 开启1ms循环定时器
    mqtt_init();                                                       // mqtt连接函数
    while (true)
    {
        keep_mqtt(); // mqtt保活
    }
}

bool repeating_timer_callback(struct repeating_timer *t)
{
    MilliTimer_Handler();
    return true;
}

void mqtt_init(void)
{
    int ret;
    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    NewNetwork(&n, MQTT_SOCKET);
    ConnectNetwork(&n, mqtt_params.server_ip, 1883);
    MQTTClientInit(&c, &n, 1000, mqtt_send_buff, MQTT_SEND_BUFF_SIZE, mqtt_recv_buff, MQTT_RECV_BUFF_SIZE);
    data.willFlag = 0;
    data.MQTTVersion = 3;
    data.clientID.cstring = mqtt_params.clientid;
    data.username.cstring = mqtt_params.username;
    data.password.cstring = mqtt_params.passwd;
    data.keepAliveInterval = 30;
    data.cleansession = 1;

    // 连接mqtt服务器，如果连接失败则继续重连
    connOK = MQTTConnect(&c, &data);
    printf("Connected:%s\r\n", connOK == 0 ? "success" : "failed");
    while (connOK)
    {
        sleep_ms(50);
        connOK = MQTTConnect(&c, &data);
        printf("Connected:%s\r\n", connOK == 0 ? "success" : "failed");
    }

    // 订阅主题，如果订阅失败则继续订阅
    ret = MQTTSubscribe(&c, mqtt_params.subtopic, mqtt_params.QOS, messageArrived);
    printf("Subscribing to %s\r\n", mqtt_params.subtopic);
    printf("Subscribed:%s\r\n", ret == 0 ? "success" : "failed");
    while (ret)
    {
        sleep_ms(50);
        ret = MQTTSubscribe(&c, mqtt_params.subtopic, mqtt_params.QOS, messageArrived);
        printf("Subscribing to %s\r\n", mqtt_params.subtopic);
        printf("Subscribed:%s\r\n", ret == 0 ? "success" : "failed");
    }

    sleep_ms(50);
    // 发布消息
    MQTTMessage pubmessage = {
        .qos = QOS0,
        .retained = 0,
        .dup = 0,
        .id = 0,
    };
    pubmessage.payload = "hello mqtt!";
    pubmessage.payloadlen = strlen(pubmessage.payload);
    MQTTPublish(&c, mqtt_params.pubtopic, &pubmessage);
    printf("TX:%s\r\n", pubmessage.payload);
}

void messageArrived(MessageData *md)
{
    unsigned char messagebuffer[512];
    MQTTMessage *message = md->message;

    if (0)
    {
        memcpy(messagebuffer, (char *)message->payload, (int)message->payloadlen);
        *(messagebuffer + (int)message->payloadlen + 1) = '\n';
        printf("%s\r\n", messagebuffer);
    }

    if (0)
        printf("%.*s", (int)message->payloadlen, (char *)message->payload);
    else
        printf("%s%.*s%s%s", "Rx:", (int)message->payloadlen, (char *)message->payload, mqtt_params.QOS, "\r\n");
}

void keep_mqtt(void)
{
    if (MQTTYield(&c, 30))
    {
        mqtt_init();
    }
}